package com.mi.rof.config;



import com.mi.rof.engineer.action.PreviewAction;
import com.mi.rof.engineer.entity.RepairOrderEvents;
import com.mi.rof.engineer.entity.RepairOrderStates;
import com.mi.rof.engineer.guard.OrderAcceptGuard;
import com.mi.rof.engineer.guard.OrderReviewGuard;
import com.mi.rof.engineer.guard.PreviewGuard;
import com.mi.rof.engineer.service.SmsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.listener.StateMachineListener;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;

import javax.annotation.Resource;
import java.util.EnumSet;
/**
 * @author zwq
 */
@Slf4j
@Configuration
@EnableStateMachineFactory(name = "StateMachineFactory")
public class RepairOrderStateMachineConfig extends StateMachineConfigurerAdapter<RepairOrderStates, RepairOrderEvents> {

    public static final String MACHINE_ID = "repairOrderMachine";

    @Resource
    private SmsService smsService;
    /**
     * 配置状态机的初始状态
     * @param states 状态机状态配置
     * @throws Exception SystemException
     */
    @Override
    public void configure(StateMachineStateConfigurer<RepairOrderStates, RepairOrderEvents> states) throws Exception {
        states.withStates()
                .initial(RepairOrderStates.ORDER_SUBMITTED)
                .choice(RepairOrderStates.CHECK_CONFIRM)
                .choice(RepairOrderStates.PREVIEW)
                .choice(RepairOrderStates.CHECK_REVIEWED)
                .states(EnumSet.allOf(RepairOrderStates.class));
    }

    /**
     * 配置状态机的configuration
     * @param config 状态机配置
     * @throws Exception  SystemException
     */
    @Override
    public void configure(StateMachineConfigurationConfigurer<RepairOrderStates, RepairOrderEvents> config) throws Exception {
        config.withConfiguration()
                .machineId(MACHINE_ID)
                .autoStartup(false)
                .listener(listener());
    }

    /**
     * 配置状态机的事件关系
     * @param transitions 状态机事件配置
     * @throws Exception SystemException
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<RepairOrderStates, RepairOrderEvents> transitions) throws Exception {
        transitions
                .withExternal().source(RepairOrderStates.ORDER_SUBMITTED)
                    .target(RepairOrderStates.ORDER_PENDING_CONFIRM)
                    .event(RepairOrderEvents.AFTER_SUBMIT).and()
                //工单待确认到现场确认
                .withExternal().source(RepairOrderStates.ORDER_PENDING_CONFIRM).target(RepairOrderStates.CHECK_CONFIRM)
                    .event(RepairOrderEvents.UPLOAD_FAULT_INFO)
                    .and()
                // 工程师现场确认的分支
                .withChoice().source(RepairOrderStates.CHECK_CONFIRM)
                    .first(RepairOrderStates.ORDER_ACCEPTED, new OrderAcceptGuard()).last(RepairOrderStates.ORDER_WITHDRAWN)
                    .and()
                //工单撤回到工单更新并成为待确认
                .withExternal().source(RepairOrderStates.ORDER_WITHDRAWN).target(RepairOrderStates.ORDER_PENDING_CONFIRM)
                    .event(RepairOrderEvents.ORDER_UPDATE).and()
                // 工单已接受到工程师预检
                .withExternal().source(RepairOrderStates.ORDER_ACCEPTED).target(RepairOrderStates.PREVIEW)
                    .event(RepairOrderEvents.PRE_INSPECT).and()
                //预检的分支条件，物料是否就绪
                .withChoice().source(RepairOrderStates.PREVIEW)
                    .first(RepairOrderStates.MATERIAL_READY, new PreviewGuard(), new PreviewAction())
                    .last(RepairOrderStates.MATERIAL_WAITING)
                    .and()
                //物料从等待中到物料就绪
                .withExternal().source(RepairOrderStates.MATERIAL_WAITING)
                    .target(RepairOrderStates.MATERIAL_READY)
                    .event(RepairOrderEvents.MATERIAL_DISTRIBUTION)
                    .and()
                //物料就绪到工程师检修
                .withExternal().source(RepairOrderStates.MATERIAL_READY)
                    .target(RepairOrderStates.ORDER_SERVICED)
                    .event(RepairOrderEvents.REPAIR)
                    .and()
                //已检修到判断复核
                .withExternal().source(RepairOrderStates.ORDER_SERVICED).target(RepairOrderStates.CHECK_REVIEWED)
                    .event(RepairOrderEvents.REVIEW)
                    .and()
                //分支  判断复核到已复核或者重回工单已接受
                .withChoice().source(RepairOrderStates.CHECK_REVIEWED)
                    .first(RepairOrderStates.ORDER_REVIEWED,new OrderReviewGuard())
                    .last(RepairOrderStates.ORDER_ACCEPTED)
                    .and()
                // 已复核到已完成
                .withExternal().source(RepairOrderStates.ORDER_REVIEWED).target(RepairOrderStates.ORDER_COMPLETED)
                    .event(RepairOrderEvents.PAY)
                    .and()
                //已完成到工单结束
                .withExternal().source(RepairOrderStates.ORDER_COMPLETED).target(RepairOrderStates.ORDER_ENDED)
                    .event(RepairOrderEvents.RETURN)
                    .and();

    }

    @Bean
    public StateMachineListener<RepairOrderStates, RepairOrderEvents> listener() {
        return new StateMachineListenerAdapter<RepairOrderStates, RepairOrderEvents>() {
            @Override
            public void stateChanged(State<RepairOrderStates, RepairOrderEvents> from, State<RepairOrderStates, RepairOrderEvents> to) {
                String message = String.format("工单状态从\"%s\"变更为\"%s\"", from.getId().getMsg(),to.getId().getMsg());
                log.info(message);
            }
        };
    }


}
